package com.suray.basic.wcs.plc.pojo.oper.lifter;

import com.suray.basic.wcs.plc.core.PlcOffset;
import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.enums.PlcDeviceType;
import com.suray.basic.wcs.plc.pojo.DeviceBase;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.basic.wcs.plc.utils.LifterTaskProcess;

import java.io.IOException;

/**
 * @author shaozn
 * @date 2020/1/22 - 16:21
 * @Description 提升机
 */
public class LifterOper extends DeviceBase {

    final protected static int OPER_OFF = 0;
    final protected static int OPER_ON = 1;
    // 提升机当前任务 读
    private final static PlcOffset CURR_TASK_NO_R = new PlcOffset(0, null);
    // 提升机任务完成编号 读写
    private final static PlcOffset FINISH_TASK_NO_RW = new PlcOffset(1, null);
    // 提升机当前层 读
    private final static PlcOffset CURR_LAYER_R = new PlcOffset(2, null);
    // 校验位 读
    private final static PlcOffset CHECK_R = new PlcOffset(3, null);
    // 提升机货物状态 4 -7
    private final static PlcOffset PALLET_EXISTED_R = new PlcOffset(4, null);
    // 提升机设备状态 读
    private final static int CONDITION_R = 8;
    // 提升机错误 读
    private final static int ERROR_R = 9;
    // 提升机锁定
    private final static int LOCK_T = 10;
    // 提升机故障码
    private final static PlcOffset ERROR_CODE = new PlcOffset(11, null);
    // 提升机任务字 写
    private final static int TASK_CODE_WT = 13;
    // 提升机任务编号 写
    private final static int TASK_NO_W = 15;
    // 小车已到位 写
    private final static int SHUTTLE_ARRIVED_W = 16;
    // 小车已驶出 写
    private final static int SHUTLLE_OUTED_W = 17;
    // 提升机任务清除 写
    private final static int TASK_CLEAR_W = 18;
    // 提升机故障清除 写
    private final static int ERROR_CLEAR_W = 19;
    // 提升机上位锁 写
    private final static int LOCK_W = 20;
    // 提升机密码
    private final static int PASSWORD = 21;

    protected static int bit1;
    protected static int bit2;
    protected static int bit3;
    protected static int bit4;
    protected static int bit5;
    protected static int bit6;
    protected static int bit7;
    protected static int bit8;

    protected static int bit9;
    protected static int bit10;
    protected static int bit11;
    protected static int bit12;
    protected static int bit13;
    protected static int bit14;
    protected static int bit15;
    protected static int bit16;

    protected ForkLifterOperData forkLifterOperData;

    public void setForkLifterOperData(ForkLifterOperData forkLifterOperData) {
        this.forkLifterOperData = forkLifterOperData;
    }

    public String getTaskDes() {
        return forkLifterOperData.getTaskDes();
    }

    public void setTaskDes(String taskDes) {
        this.forkLifterOperData.setTaskDes(taskDes);
    }

    public Integer getCode() {
        return forkLifterOperData.getCode();
    }

    public void setCode(Integer code) {
        this.forkLifterOperData.setCode(code);
    }

    public Integer getTaskId() {
        return forkLifterOperData.getTaskId();
    }

    public void setTaskId(Integer taskId) {
        this.forkLifterOperData.setTaskId(taskId);
    }

    public LifterTaskProcess getTaskProcess() {
        return forkLifterOperData.getTaskProcess();
    }

    public void clearTask() {
        this.forkLifterOperData.setTaskProcess(null);
        this.forkLifterOperData.setTaskId(null);
        this.forkLifterOperData.setCode(null);
    }

    public void setTaskProcess(LifterTaskProcess taskProcess) {
        this.forkLifterOperData.setTaskProcess(taskProcess);
    }

    public LifterOper(PlcDeviceType plcDeviceType, int startNo, String deviceName, int deviceNo, Coord coord,
                      Location location, Coord lockLocation, long deviceId, Integer gridzMax, Integer gridzRelative,
                      int plcId) {
        super(plcDeviceType, startNo, deviceName, deviceNo, coord, location, lockLocation, deviceId, gridzMax,
                gridzRelative, plcId);
        if (plcDeviceType.equals(PlcDeviceType.PANASONIC_LIFT) || plcDeviceType.equals(PlcDeviceType.TAMAGAWA_LIFTER)
                || plcDeviceType.equals(PlcDeviceType.FORK_LIFTER)
                || PlcDeviceType.AUTOMATIC_LIFTER == plcDeviceType) {
            // 如果是松下提升机
            bit1 = 0;
            bit2 = 1;
            bit3 = 2;
            bit4 = 3;
            bit5 = 4;
            bit6 = 5;
            bit7 = 6;
            bit8 = 7;
            bit9 = 8;
            bit10 = 9;
            bit11 = 10;
            bit12 = 11;
            bit13 = 12;
            bit14 = 13;
            bit15 = 14;
            bit16 = 15;
        } else if (plcDeviceType.equals(PlcDeviceType.SIEMENS_HOIST)) {
            // 如果是西门子提升机
            bit1 = 8;
            bit2 = 9;
            bit3 = 10;
            bit4 = 11;
            bit5 = 12;
            bit6 = 13;
            bit7 = 14;
            bit8 = 15;
            bit9 = 0;
            bit10 = 1;
            bit11 = 2;
            bit12 = 3;
            bit13 = 4;
            bit14 = 5;
            bit15 = 6;
            bit16 = 7;
        } else {
            throw new RuntimeException("不支持的提升机类型！");
        }

        this.forkLifterOperData = new ForkLifterOperData();
    }

    /**
     * 获取提升机真实层数
     *
     * @param gridzRelative
     * @param endz
     * @return
     */
    public static int getGridzRaletive(int gridzRelative, Integer endz) {
        Integer endLayer = endz - gridzRelative + 1;
        return endLayer;
    }

    /**
     * 获取提升机当前任务编号
     *
     * @return
     */
    public int getHoistCurrentTaskNo() {
        return readPlc(CURR_TASK_NO_R);
    }

    /**
     * 获取提升机完成编号
     *
     * @return
     */
    public int getHoistFinalTaskNo() {
        return readPlc(FINISH_TASK_NO_RW);
    }

    /**
     * 提升机当前层
     *
     * @return 0表示非平层
     */
    public int getHoistCurrentLayer() {
        return readPlc(CURR_LAYER_R);
    }

    /**
     * 心跳信号(1-60循环）
     *
     * @return
     */
    public int getCheckNo() {
        return readPlc(CHECK_R);
    }



    /**
     * 提升机故障码
     *
     * @return
     */
    public int getLifterErrorCode() {
        return readPlc(ERROR_CODE);
    }


    /**
     * WCS清理提升机任务完成编号
     *
     * @return
     */
    public void setHoistFinalTaskNoClear() throws IOException {
        oper("WCS清理提升机任务完成编号", this.getClass(), FINISH_TASK_NO_RW.getAddressOffset(), 10, 0);
    }

    /**
     * 目标层左右是否有货
     *
     * @param floor    层 提升机内部的层传1-10任意数字
     * @param location 位置
     * @return 有货 true
     */
    public boolean isPalletExisted(Integer floor, Location location) {
        if (floor > 99 || floor < 1) {
            throw new IllegalArgumentException("输送线状态层数参数异常");
        }
        if (location.equals(Location.LEFT)) {
            int index = PALLET_EXISTED_R.getAddressOffset();
            int k = (bit1 + (floor - 1) * 6) % 16;
            index = index + (int) (((floor - 1) * 6) / 16);
            return readPlc(new PlcOffset(index, k)) == 1;
        } else if (location.equals(Location.RIGHT)) {
            int index = PALLET_EXISTED_R.getAddressOffset();
            int k = (bit1 + 3 + (floor - 1) * 6) % 16;
            index = index + (int) ((3 + (floor - 1) * 6) / 16);
            return readPlc(new PlcOffset(index, k)) == 1;
        } else if (location.equals(Location.INSIDE)) {
            return isHaveCargo();
        } else {
            throw new IllegalArgumentException("传入位置数参数异常");
        }
    }

    /**
     * 运行状态
     *
     * @param floor    层 提升机内部的层传1-10任意数字
     * @param location 位置
     * @return true 运行
     */
    public boolean isFacilityExisted(Integer floor, Location location) {
        if (floor > 99 || floor < 1) {
            throw new IllegalArgumentException("输送线状态层数参数异常");
        }
        if (location.equals(Location.LEFT)) {
            int index = PALLET_EXISTED_R.getAddressOffset();
            int k = (bit2 + (floor - 1) * 6) % 16;
            index = index + (int) (((bit2 - bit1) + (floor - 1) * 6) / 16);
            return readPlc(new PlcOffset(index, k)) == 1;
        } else if (location.equals(Location.RIGHT)) {

            int index = PALLET_EXISTED_R.getAddressOffset();
            int k = (bit2 + 3 + (floor - 1) * 6) % 16;
            index = index + (int) (((bit2 - bit1) + 3 + (floor - 1) * 6) / 16);
            return readPlc(new PlcOffset(index, k)) == 1;
        } else if (location.equals(Location.INSIDE)) {
            return !isHoistConveyInsideStop();
        } else {
            throw new IllegalArgumentException("传入位置数参数异常");
        }
    }

    /**
     * *
     *
     * @param floor    层 提升机内部的层传1-10任意数字
     * @param location 位置
     * @return 有货 故障
     */
    public boolean isFacilityProblem(Integer floor, Location location) {
        if (floor > 10 || floor < 1) {
            throw new IllegalArgumentException("输送线状态层数参数异常");
        }
        if (location.equals(Location.LEFT)) {
            int index = PALLET_EXISTED_R.getAddressOffset();
            // 算字节
            int k = (bit3 + (floor - 1) * 6) % 16;
            // 算第几位
            index = index + (int) (((bit3 - bit1) + (floor - 1) * 6) / 16);
            return readPlc(new PlcOffset(index, k)) == 1;
        } else if (location.equals(Location.RIGHT)) {
            int index = PALLET_EXISTED_R.getAddressOffset();
            int k = (bit3 + 3 + (floor - 1) * 6) % 16;
            index = index + (int) (((bit3 - bit1) + 3 + (floor - 1) * 6) / 16);
            return readPlc(new PlcOffset(index, k)) == 1;
        } else {
            throw new IllegalArgumentException("传入位置数参数异常");
        }
    }

    /**
     * 是否为自动模式
     *
     * @return true 自动 false 非自动
     */
    public boolean isAutoMode() {
        return readPlc(new PlcOffset(CONDITION_R, bit1)) == 1;
    }

    /**
     * 提升机是否就绪
     *
     * @return true为已就绪
     */
    public boolean isReady() {
        return readPlc(new PlcOffset(CONDITION_R, bit2)) == 1;
    }

    /**
     * 确认提升机内有车
     *
     * @return true为有车
     */
    public boolean isHaveShuttle() {
        return readPlc(new PlcOffset(CONDITION_R, bit3)) == 1;
    }

    /**
     * 提升机运行状态
     *
     * @return true为运行中
     */
    public boolean isRuning() {
        return readPlc(new PlcOffset(CONDITION_R, bit4)) == 1;
    }

    /**
     * 确认提升机是否到位
     *
     * @return true为已到位
     */
    public boolean isArrived() {
        return readPlc(new PlcOffset(CONDITION_R, bit5)) == 1;
    }

    /**
     * 提升机是否急停
     *
     * @return true为急停
     */
    public boolean isEmergencyStop() {
        return readPlc(new PlcOffset(CONDITION_R, bit6)) == 1;
    }

    /**
     * 确认提升机内有无货物
     *
     * @return true 为有货
     */
    public boolean isHaveCargo() {
        return readPlc(new PlcOffset(CONDITION_R, bit7)) == 1;
    }

    /**
     * 确认提升机货物是否到位
     *
     * @return true为已到位
     */
    public boolean isHoistGoodArrived() {
        return readPlc(new PlcOffset(CONDITION_R, bit8)) == 1;
    }

    /**
     * 确认提升机是否未阻挡
     *
     * @return true为未阻挡
     */
    public boolean isHoistBarrierPass() {
        return readPlc(new PlcOffset(CONDITION_R, bit9)) == 1;
    }

    /**
     * 确认提升机内部输送线未运行
     *
     * @return true为未运行
     */
    public boolean isHoistConveyInsideStop() {
        return !(readPlc(new PlcOffset(CONDITION_R, bit10)) == 1);
    }

    /**
     * 确认提升机本地远程
     *
     * @return true 远程
     */
    public boolean isRemoteMode() {
        return readPlc(new PlcOffset(CONDITION_R, bit11)) == 1;
    }

    /**
     * 确认锁状态
     *
     * @return true 锁定
     */

    public boolean lockState() {
        return readPlc(new PlcOffset(CONDITION_R, bit12)) == 1;
    }

    // 故障模块

    /**
     * 故障：提升机前限位超限
     *
     * @return true 为故障
     */
    public boolean isHoistFontLimited() {
        return readPlc(new PlcOffset(ERROR_R, bit1)) == 1;
    }

    /**
     * 故障：提升机后限位超限
     *
     * @return true 为故障
     */
    public boolean isHoistBackLimited() {
        return readPlc(new PlcOffset(ERROR_R, bit2)) == 1;
    }

    /**
     * 故障：提升机上限位超限
     *
     * @return true 为故障
     */
    public boolean isHoistUpLimited() {
        return readPlc(new PlcOffset(ERROR_R, bit3)) == 1;
    }

    /**
     * 故障：提升机下限位超限
     *
     * @return true 为故障
     */
    public boolean isHoistDownLimited() {
        return readPlc(new PlcOffset(ERROR_R, bit4)) == 1;
    }

    /**
     * 故障：提升机条码读取异常
     *
     * @return true 为故障
     */
    public boolean isHoistBarReadCorrect() {
        return readPlc(new PlcOffset(ERROR_R, bit5)) == 1;
    }

    /**
     * 故障：提升机条码范围异常
     *
     * @return true 为故障
     */
    public boolean isHoistBarRangeCorrect() {
        return readPlc(new PlcOffset(ERROR_R, bit6)) == 1;
    }

    /**
     * 故障:电子警报
     *
     * @return true 故障
     */
    public boolean isAlarm() {
        return readPlc(new PlcOffset(ERROR_R, bit7)) == 1;
    }

    /**
     * 故障：提升机任务字非法
     *
     * @return true为故障
     */
    public boolean isHoistTaskCodeCorrect() {
        return readPlc(new PlcOffset(ERROR_R, bit8)) == 1;
    }

    /**
     * 故障：提升机起点位置无货
     *
     * @return true为故障
     */
    public boolean isHoistStartEmpty() {
        return readPlc(new PlcOffset(ERROR_R, bit9)) == 1;
    }

    /**
     * 故障：提升机终点位置有货
     *
     * @return true为故障
     */
    public boolean isHoistEndEmpty() {
        return readPlc(new PlcOffset(ERROR_R, bit10)) == 1;
    }

    /**
     * 故障：提升机平台内有货
     *
     * @return true为故障
     */
    public boolean isHoistInStock() {
        return readPlc(new PlcOffset(ERROR_R, bit11)) == 1;
    }

    /**
     * 故障：小车未到位
     *
     * @return true 为故障
     */
    public boolean isHoistShuttleArrived() {
        return readPlc(new PlcOffset(ERROR_R, bit12)) == 1;
    }

    /**
     * 故障：小车未驶离
     *
     * @return true 为故障
     */
    public boolean isHoistShuttleOuted() {
        return readPlc(new PlcOffset(ERROR_R, bit13)) == 1;
    }

    /**
     * 提升机内链条机前边缘超限
     *
     * @return true 故障
     */
    public boolean isChainFontError() {
        return readPlc(new PlcOffset(ERROR_R, bit14)) == 1;
    }

    /**
     * 提升机内链条机后边缘超限
     *
     * @return true 故障
     */
    public boolean isChainBackError() {
        return readPlc(new PlcOffset(ERROR_R, bit15)) == 1;
    }

    /**
     * 边缘超限
     *
     * @return true 故障
     */

    public boolean isEdgeTransfinite() {
        return readPlc(new PlcOffset(ERROR_R, bit16)) == 1;
    }

    /**
     * 设置小车已到位
     *
     * @return
     */
    public void setHoistShuttleArrived() throws IOException {
        oper("设置小车已到位", this.getClass(), SHUTTLE_ARRIVED_W, 10, OPER_ON);
    }

    /**
     * 设置小车已驶出
     *
     * @return
     */
    public void setHoistShuttleOuted() throws IOException {
        oper("设置小车已驶出", this.getClass(), SHUTLLE_OUTED_W, 10, OPER_ON);
    }

    /**
     * 清除当前提升机任务
     * w
     *
     * @return
     */
    public void setHoistTaskClear() throws IOException {
        oper("清除当前提升机任务", this.getClass(), TASK_CLEAR_W, 10, OPER_ON);
    }

    /**
     * 清除当前提升机故障
     *
     * @return
     */
    public void setHoistCurrentErrorClear() throws IOException {
        oper("清除当前提升机故障", this.getClass(), ERROR_CLEAR_W, 10, OPER_ON);
    }

    /**
     * 提升机上锁
     */
    public void lockHoist(int password) throws IOException {
        int[] cmd = {OPER_ON, password};
        LoggerUtil.info("锁定提升机，密码：" + password, this.getClass());
        oper("提升机上锁", this.getClass(), LOCK_W, 10, cmd);
    }

    /**
     * 提升机解锁
     */
    public void unlockHoist(int password) throws IOException {
        int[] cmd = {OPER_OFF, password};
        LoggerUtil.info("解锁提升机，密码：" + password, this.getClass());
        oper("提升机上锁", this.getClass(), LOCK_W, 10, cmd);
    }

    /**
     * 获取是否有错误，0为无错
     *
     * @return 0为无错
     */
    public int getError() {
        return readPlc(new PlcOffset(ERROR_R, 0));
    }

    /**
     * 写任务字以及任务号
     *
     * @param code
     * @param taskNo
     */
    public void callLift(int code, int taskNo) throws IOException {

        if (this.getPlcDeviceType().equals(PlcDeviceType.TAMAGAWA_LIFTER) || PlcDeviceType.AUTOMATIC_LIFTER.equals(this.getPlcDeviceType())) {
            int[] liftWord = {code & 0xffff, (code >> 16) & 0xff, taskNo};
            oper("写任务字以及任务号", this.getClass(), TASK_CODE_WT, 10, liftWord);
        } else if (this.getPlcDeviceType().equals(PlcDeviceType.PANASONIC_LIFT) || this.getPlcDeviceType().equals(PlcDeviceType.SIEMENS_HOIST)) {
            int[] liftWord = {(code >> 16) & 0xff, code & 0xffff, taskNo};
            oper("写任务字以及任务号", this.getClass(), TASK_CODE_WT, 10, liftWord);
        }
    }

    public int readBit() {
        return readPlc(new PlcOffset(TASK_CODE_WT, 0));
    }

    /**
     * 提升机未就绪wcs下发任务 true 故障
     */
    public boolean notReadyHoist() {
        return readPlc(new PlcOffset(LOCK_T, bit1)) == 1;
    }

    /**
     * wcs锁定失败 true 故障
     */
    public boolean lockProblem() {
        return readPlc(new PlcOffset(LOCK_T, bit2)) == 1;
    }

    /**
     * 解锁失败
     *
     * @return true 故障
     */
    public boolean unlockProblem() {
        return readPlc(new PlcOffset(LOCK_T, bit3)) == 1;
    }

    /**
     * 与主控断开 return true 故障
     */
    public boolean disconnect() {
        return readPlc(new PlcOffset(LOCK_T, bit4)) == 1;
    }

    /**
     * 链条机故障 return true 故障
     */
    public boolean chainFault() {
        return readPlc(new PlcOffset(LOCK_T, bit5)) == 1;
    }

    /**
     * 辊道机故障 return true 故障
     */
    public boolean rollerTableFault() {
        return readPlc(new PlcOffset(LOCK_T, bit6)) == 1;
    }

    /**
     * 移栽升降机故障 return true 故障
     */
    public boolean transplantLiftFailure() {
        return readPlc(new PlcOffset(LOCK_T, bit7)) == 1;
    }

    /**
     * 提升机前限位超限
     *
     * @return
     */
    public boolean overFrontLimit() {
        return readPlc(new PlcOffset(ERROR_R, bit1)) == 1;
    }

    /**
     * 提升机后限位超限
     *
     * @return
     */
    public boolean overBackLimit() {
        return readPlc(new PlcOffset(ERROR_R, bit2)) == 1;
    }

    /**
     * 提升机上限位超限
     *
     * @return
     */
    public boolean overUpLimit() {
        return readPlc(new PlcOffset(ERROR_R, bit3)) == 1;
    }

    /**
     * 提升机下限位超限
     *
     * @return
     */
    public boolean overDownLimit() {
        return readPlc(new PlcOffset(ERROR_R, bit4)) == 1;
    }

    /**
     * 扫码读取故障
     *
     * @return
     */
    public boolean scanFault() {
        return readPlc(new PlcOffset(ERROR_R, bit5)) == 1;
    }

    /**
     * 扫码数值范围错误
     *
     * @return
     */
    public boolean scanNumRangeFault() {
        return readPlc(new PlcOffset(ERROR_R, bit6)) == 1;
    }

    /**
     * 伺服报警
     *
     * @return
     */
    public boolean servoFault() {
        return readPlc(new PlcOffset(ERROR_R, bit7)) == 1;
    }

    /**
     * 提升机任务字非法
     *
     * @return
     */
    public boolean lifterTaskNoIllegal() {
        return readPlc(new PlcOffset(ERROR_R, bit8)) == 1;
    }

    /**
     * 提升机起始位置无货
     *
     * @return
     */
    public boolean noCargoStartLocation() {
        return readPlc(new PlcOffset(ERROR_R, bit9)) == 1;
    }

    /**
     * 提升机终点位置有货
     *
     * @return
     */
    public boolean hasCargoEndLocation() {
        return readPlc(new PlcOffset(ERROR_R, bit10)) == 1;
    }

    /**
     * 提升机内有货
     *
     * @return
     */
    public boolean hasCargoInnerLifter() {
        return readPlc(new PlcOffset(ERROR_R, bit11)) == 1;
    }

    /**
     * 小车未到位
     *
     * @return
     */
    public boolean rgvNotArrived() {
        return readPlc(new PlcOffset(ERROR_R, bit12)) == 1;
    }

    /**
     * 小车未驶离
     *
     * @return
     */
    public boolean rgvNotLeave() {
        return readPlc(new PlcOffset(ERROR_R, bit13)) == 1;
    }

    /**
     * 提升机内链条机前边缘超限
     *
     * @return
     */
    public boolean lifterOverChainFrontLimit() {
        return readPlc(new PlcOffset(ERROR_R, bit14)) == 1;
    }

    /**
     * 提升机内链条机后边缘超限
     *
     * @return
     */
    public boolean lifterOverChainBackLimit() {
        return readPlc(new PlcOffset(ERROR_R, bit15)) == 1;
    }

    /**
     * 对接链条机边缘超限
     *
     * @return
     */
    public boolean overConnectChainLimit() {
        return readPlc(new PlcOffset(ERROR_R, bit16)) == 1;
    }

    /**
     * 提升机是否故障
     *
     * @return
     */
    public boolean isLifterFault() {
        int seed = (1 << bit1) | (1 << bit2) | (1 << bit3) | (1 << bit4) | (1 << bit5) | (1 << bit6) | (1 << bit7);
        return readPlc(new PlcOffset(ERROR_R, null)) > 0 ||
                (readPlc(new PlcOffset(LOCK_T, null)) & seed) > 0;
    }

    /**
     * 写入提升机密码
     */

//	public void writePassword(int password) throws IOException {
//		oper("写入提升机密码", this.getClass(), PASSWORD, 10, password);
//	}

}
